MinCamlをApple M1へ移植した(2周目)
https://gyazo.com/6707ce3a47b32b00326689b2c293dcd3
1周目は試行錯誤しつつでゴチャゴチャしてたので、色々整理するためにもう一回AArch64へ移植してみた。
thata/min-caml-aarcht64(AArch64への移植)
esumii/min-caml(オリジナル)
オリジナルのMinCamlをcloneする
code:sh
文字コード変換(EUC-JP → UTF-8)
code:sh
$ nkf -Ew --overwrite nkf --guess **/* | grep EUC | awk 'BEGIN{FS=":"} {print $1}'
AArch64ディレクトリを作成
PowerPC ディレクトリをコピーして AArch64 ディレクトリを作成して、
code:sh
$ cp -r PowerPC AArch64
CPUアーキテクチャに依存したコードを展開するスクリプト to_aarch64 を用意する。
code:to_aarch64
ln -sf AArch64/{*.ml{,i},libmincaml.S} .
cd test; ln -sf AArch64/{,too}manyargs.ml .; cd ..
cd shootout; ln -sf AArch64/Makefile .; cd ..
cd bytemark; ln -sf AArch64/Makefile .; cd ..
cd min-rt; ln -sf AArch64/globals.s .; cd ..
MinCamlコンパイラをビルド
AArch64 ディレクトリにあるCPUアーキテクチャ依存コード(現時点では PowerPC のコードを出力する)をソースコードに反映し、MinCamlコンパイラをビルドする。
code:sh
$ ./to_aarch64
$ make min-caml
利用しているOCamlのバージョンによっては copy_int32 が無いよーとエラーが出るので、その場合は float.c を以下のように 修正する
code:diff
diff --git a/float.c b/float.c
index 1508d9e..1165150 100644
--- a/float.c
+++ b/float.c
@@ -11,11 +11,11 @@ typedef union {
value gethi(value v) {
dbl d;
d.d = Double_val(v);
- return copy_int32(d.i0); + return caml_copy_int32(d.i0); }
value getlo(value v) {
dbl d;
d.d = Double_val(v);
- return copy_int32(d.i1); + return caml_copy_int32(d.i1); }
ビルドしたMinCamlを動かしてみる。以下のようにヘルプが出力されればOK
code:sh
$ ./min-caml --help
Mitou Min-Caml Compiler (C) Eijiro Sumii
-inline maximum size of functions inlined
-iter maximum number of optimizations iterated
-help Display this list of options
--help Display this list of options
整数を出力するだけのプログラムをコンパイル
まずは以下のような整数を出力するだけのプログラムをコンパイルできるようにする。
code:test/4649.ml
let x = 4649 in
let y = 5963 in
print_int x;
print_newline ();
print_int y;
print_newline ()
先ほどビルドしたMinCamlを使って test/4649.ml をコンパイルすると、
code:sh
./min-caml test/4649
以下のようなPowerPCのアセンブリコードが出力される。これをAArch64のコードが出力されるよう修正していく。
code:test/4649.s
.text
.globl _min_caml_start
.align 2
_min_caml_start: # main entry point
mflr r0
stmw r30, -8(r1)
stw r0, 8(r1)
stwu r1, -96(r1)
# main program starts
li r2, 4649
li r5, 5963
stw r5, 0(r3)
mflr r31
stw r31, 4(r3)
addi r3, r3, 8
bl min_caml_print_int
subi r3, r3, 8
lwz r31, 4(r3)
mtlr r31
mflr r31
stw r31, 4(r3)
addi r3, r3, 8
bl min_caml_print_newline
subi r3, r3, 8
lwz r31, 4(r3)
mtlr r31
lwz r2, 0(r3)
mflr r31
stw r31, 4(r3)
addi r3, r3, 8
bl min_caml_print_int
subi r3, r3, 8
lwz r31, 4(r3)
mtlr r31
mflr r31
stw r31, 4(r3)
addi r3, r3, 8
bl min_caml_print_newline
subi r3, r3, 8
lwz r31, 4(r3)
mtlr r31
# main program ends
lwz r1, 0(r1)
lwz r0, 8(r1)
mtlr r0
lmw r30, -8(r1)
blr
libmincaml.SのAArch64対応
MinCaml本体のAArch64対応を始める前に、MinCamlのライブラリ関数 libmincaml.S のAArch64対応を行う。オリジナルの libmincaml.S はPowerPCアセンブリで書かれているため、これをAArch64に書き直す。
以下のCのコード libmincaml.c を用意して、
code:AArch64/libmincaml.c
// NOTE: コンパイル後のシンボルのプリフィックスに _ がつくのを避ける
void min_caml_print_int(long n) asm("min_caml_print_int");
void min_caml_print_newline() asm("min_caml_print_newline");
void min_caml_print_int(long n) {
printf("%ld", n);
}
void min_caml_print_newline() {
printf("\n");
}
以下のコマンドでアセンブリコードを生成して libmincaml.S へ出力する。
code:sh
$ gcc -S -o AArch64/libmincaml.S AArch64/libmincaml.c
「整数を出力するだけのプログラム」をAArch64で動くように修正
test/4649.ml がAArch64のアセンブリコードを出力できるようMinCaml本体を以下のように修正する。主に以下の修正を行った。
利用するレジスタを定義
変数のバイト長を4バイト(32ビット)から8バイト(64ビット)に修正
Li対応(li → mov)
Save対応(stw → str)
Restore対応(lwz → ldr)
ライブラリ関数呼び出し対応
プログラムの開始処理と終了処理のAArch64対応
code:diff
diff --git a/AArch64/asm.ml b/AArch64/asm.ml
index 491c82c..12b71f7 100644
--- a/AArch64/asm.ml
+++ b/AArch64/asm.ml
@@ -43,20 +43,22 @@ type prog = Prog of (Id.l * float) list * fundef list * t
let fletd(x, e1, e2) = Let((x, Type.Float), e1, e2)
let seq(e1, e2) = Let((Id.gentmp Type.Unit, Type.Unit), e1, e2)
+(* x29(fp) と x30(lr) は除外 *)
+(* x28 は sp として、x27 は hp として、x26 は tmp として利用するため除外 *)
+
let regs = (* Array.init 27 (fun i -> Printf.sprintf "_R_%d" i) *)
- [| "%r2"; "%r5"; "%r6"; "%r7"; "%r8"; "%r9"; "%r10";
- "%r11"; "%r12"; "%r13"; "%r14"; "%r15"; "%r16"; "%r17"; "%r18";
- "%r19"; "%r20"; "%r21"; "%r22"; "%r23"; "%r24"; "%r25"; "%r26";
- "%r27"; "%r28"; "%r29"; "%r30" |]
+ [| "%x0"; "%x1"; "%x2"; "%x3"; "%x4"; "%x5"; "%x6"; "%x7"; "%x8"; "%x9"; "%x10";
+ "%x11"; "%x12"; "%x13"; "%x14"; "%x15"; "%x16"; "%x17"; "%x18"; "%x19"; "%x20";
+ "%x21"; "%x22"; "%x23"; "%x24"; "%x25" |]
let fregs = Array.init 32 (fun i -> Printf.sprintf "%%f%d" i)
let allregs = Array.to_list regs
let allfregs = Array.to_list fregs
let reg_cl = regs.(Array.length regs - 1) (* closure address (caml2html: sparcasm_regcl) *)
let reg_sw = regs.(Array.length regs - 2) (* temporary for swap *)
let reg_fsw = fregs.(Array.length fregs - 1) (* temporary for swap *)
-let reg_sp = "%r3" (* stack pointer *)
-let reg_hp = "%r4" (* heap pointer (caml2html: sparcasm_reghp) *)
-let reg_tmp = "%r31" (* XX ad hoc *) +let reg_sp = "%x28" (* stack pointer *)
+let reg_hp = "%x27" (* heap pointer (caml2html: sparcasm_reghp) *)
+let reg_tmp = "%x26" (* XX ad hoc *) let is_reg x = (x.0 = '%') (* super-tenuki *)
diff --git a/AArch64/emit.ml b/AArch64/emit.ml
index 323144d..59a0607 100644
--- a/AArch64/emit.ml
+++ b/AArch64/emit.ml
@@ -21,8 +21,10 @@ let locate x =
| y :: zs when x = y -> 0 :: List.map succ (loc zs)
| y :: zs -> List.map succ (loc zs) in
loc !stackmap
-let offset x = 4 * List.hd (locate x)
-let stacksize () = align ((List.length !stackmap + 1) * 4)
+
+(* NOTE: 64ビットなので 4 バイトから 8 バイトに修正 *)
+let offset x = 8 * List.hd (locate x)
+let stacksize () = align ((List.length !stackmap + 1) * 8)
let reg r =
if is_reg r
@@ -59,7 +61,8 @@ let rec g oc = function (* 命令列のアセンブリ生成 (caml2html: emit_g)
and g' oc = function (* 各命令のアセンブリ生成 (caml2html: emit_gprime) *)
(* 末尾でなかったら計算結果をdestにセット (caml2html: emit_nontail) *)
| NonTail(_), Nop -> ()
- | NonTail(x), Li(i) when -32768 <= i && i < 32768 -> Printf.fprintf oc "\tli\t%s, %d\n" (reg x) i
+ | NonTail(x), Li(i) when -32768 <= i && i < 32768 -> Printf.fprintf oc "\tmov %s, %d\n" (reg x) i
+ (* TODO: こちらは後で実装する *)
| NonTail(x), Li(i) ->
let n = i lsr 16 in
let m = i lxor (n lsl 16) in
@@ -100,14 +103,14 @@ and g' oc = function (* 各命令のアセンブリ生成 (caml2html: emit_gprim
(* 退避の仮想命令の実装 (caml2html: emit_save) *)
| NonTail(_), Save(x, y) when List.mem x allregs && not (S.mem y !stackset) ->
save y;
- Printf.fprintf oc "\tstw\t%s, %d(%s)\n" (reg x) (offset y) (reg reg_sp)
+ Printf.fprintf oc "\tstr %s, %s, %d\n" (reg x) (reg reg_sp) (offset y) | NonTail(_), Save(x, y) when List.mem x allfregs && not (S.mem y !stackset) ->
savef y;
Printf.fprintf oc "\tstfd\t%s, %d(%s)\n" (reg x) (offset y) (reg reg_sp)
| NonTail(_), Save(x, y) -> assert (S.mem y !stackset); ()
(* 復帰の仮想命令の実装 (caml2html: emit_restore) *)
| NonTail(x), Restore(y) when List.mem x allregs ->
- Printf.fprintf oc "\tlwz\t%s, %d(%s)\n" (reg x) (offset y) (reg reg_sp)
+ Printf.fprintf oc "\tldr %s, %s, %d\n" (reg x) (reg reg_sp) (offset y) | NonTail(x), Restore(y) ->
assert (List.mem x allfregs);
Printf.fprintf oc "\tlfd\t%s, %d(%s)\n" (reg x) (offset y) (reg reg_sp)
@@ -200,19 +203,21 @@ and g' oc = function (* 各命令のアセンブリ生成 (caml2html: emit_gprim
Printf.fprintf oc "\tfmr\t%s, %s\n" (reg a) (reg fregs.(0));
Printf.fprintf oc "\tmtlr\t%s\n" (reg reg_tmp)
| (NonTail(a), CallDir(Id.L(x), ys, zs)) ->
- Printf.fprintf oc "\tmflr\t%s\n" (reg reg_tmp);
g'_args oc [] ys zs;
let ss = stacksize () in
- Printf.fprintf oc "\tstw\t%s, %d(%s)\n" (reg reg_tmp) (ss - 4) (reg reg_sp);
- Printf.fprintf oc "\taddi\t%s, %s, %d\n" (reg reg_sp) (reg reg_sp) ss;
- Printf.fprintf oc "\tbl\t%s\n" x;
- Printf.fprintf oc "\tsubi\t%s, %s, %d\n" (reg reg_sp) (reg reg_sp) ss;
- Printf.fprintf oc "\tlwz\t%s, %d(%s)\n" (reg reg_tmp) (ss - 4) (reg reg_sp);
+ (* lrをスタックへ退避 *)
+ Printf.fprintf oc "\tmov %s, lr\n" (reg reg_tmp);
+ Printf.fprintf oc "\tstr %s, %s, %d\n" (reg reg_tmp) (reg reg_sp) (ss - 8); + Printf.fprintf oc "\tadd %s, %s, %d\n" (reg reg_sp) (reg reg_sp) ss;
+ Printf.fprintf oc "\tbl %s\n" x;
+ Printf.fprintf oc "\tsub %s, %s, %d\n" (reg reg_sp) (reg reg_sp) ss;
+ Printf.fprintf oc "\tldr %s, %s, %d\n" (reg reg_tmp) (reg reg_sp) (ss - 8); if List.mem a allregs && a <> regs.(0) then
Printf.fprintf oc "\tmr\t%s, %s\n" (reg a) (reg regs.(0))
else if List.mem a allfregs && a <> fregs.(0) then
Printf.fprintf oc "\tfmr\t%s, %s\n" (reg a) (reg fregs.(0));
- Printf.fprintf oc "\tmtlr\t%s\n" (reg reg_tmp)
+ (* lrをスタックから復元 *)
+ Printf.fprintf oc "\tmov lr, %s\n" (reg reg_tmp)
and g'_tail_if oc e1 e2 b bn =
let b_else = Id.genid (b ^ "_else") in
Printf.fprintf oc "\t%s\tcr7, %s\n" bn b_else;
@@ -275,18 +280,23 @@ let f oc (Prog(data, fundefs, e)) =
Printf.fprintf oc "\t.align 2\n";
List.iter (fun fundef -> h oc fundef) fundefs;
Printf.fprintf oc "_min_caml_start: # main entry point\n";
- Printf.fprintf oc "\tmflr\tr0\n";
- Printf.fprintf oc "\tstmw\tr30, -8(r1)\n";
- Printf.fprintf oc "\tstw\tr0, 8(r1)\n";
- Printf.fprintf oc "\tstwu\tr1, -96(r1)\n";
+ (* sp と hp を設定 *)
+ Printf.fprintf oc "\tadd %s, %s, 0\n" (reg reg_sp) (reg "%x0");
+ Printf.fprintf oc "\tadd %s, %s, 0\n" (reg reg_hp) (reg "%x1");
+ (* fpとlrをスタックへ退避 *)
+ Printf.fprintf oc "\tstr fp, %s, 0\n" (reg reg_sp); + Printf.fprintf oc "\tstr lr, %s, 8\n" (reg reg_sp); + Printf.fprintf oc "\tadd %s, %s, 16\n" (reg reg_sp) (reg reg_sp);
+
Printf.fprintf oc "#\tmain program starts\n";
stackset := S.empty;
stackmap := [];
g oc (NonTail("_R_0"), e);
Printf.fprintf oc "#\tmain program ends\n";
- (* Printf.fprintf oc "\tmr\tr3, %s\n" regs.(0); *)
- Printf.fprintf oc "\tlwz\tr1, 0(r1)\n";
- Printf.fprintf oc "\tlwz\tr0, 8(r1)\n";
- Printf.fprintf oc "\tmtlr\tr0\n";
- Printf.fprintf oc "\tlmw\tr30, -8(r1)\n";
- Printf.fprintf oc "\tblr\n"
+
+ (* fpとlrをスタックから復元 *)
+ Printf.fprintf oc "\tsub %s, %s, 16\n" (reg reg_sp) (reg reg_sp);
+ Printf.fprintf oc "\tldr fp, %s, 0\n" (reg reg_sp); + Printf.fprintf oc "\tstr lr, %s, 8\n" (reg reg_sp); + (* 呼び出し元へ戻る *)
+ Printf.fprintf oc "\tret\n"
diff --git a/Makefile b/Makefile
index 4d9961c..23a02f5 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
# Sumii's Makefile for Min-Caml (for GNU Make)
-#
+#
# ack.mlなどのテストプログラムをtest/に用意してmake do_testを実行すると、
# min-camlとocamlでコンパイル・実行した結果を自動で比較します。
@@ -43,7 +43,7 @@ TRASH = $(TESTS:%=test/%.s) $(TESTS:%=test/%) $(TESTS:%=test/%.res) $(TESTS:%=te
test/%.s: $(RESULT) test/%.ml
./$(RESULT) test/$*
test/%: test/%.s libmincaml.S stub.c
- $(CC) $(CFLAGS) -m32 $^ -lm -o $@
+ $(CC) $(CFLAGS) $^ -lm -o $@
test/%.res: test/%
$< > $@
test/%.ans: test/%.ml
最低限のAArch64のアセンブリコードを出力できるようになったので、以下のコマンドでコンパイル・実行する。以下のように4649と5963が表示されればOK
code:sh
$ make clean test/4649
$ ./test/4649
sp = 0x16f082ef8, hp = 0x138008000
4649
5963
フィボナッチ数を計算
次はフィボナッチ数を計算するサンプルプログラムをAArch64対応する。
code:sum.ml
let rec fib n =
if n <= 1 then n else
fib (n - 1) + fib (n - 2) in
print_int (fib 30)
主な修正箇所は以下の通り。
呼び出し元へリターン(blr → ret)
条件分岐まわりの修正(cmpw, cmpwi → cmp)
code:diff
diff --git a/AArch64/emit.ml b/AArch64/emit.ml
index 59a0607..266db34 100644
--- a/AArch64/emit.ml
+++ b/AArch64/emit.ml
@@ -81,7 +81,7 @@ and g' oc = function (* 各命令のアセンブリ生成 (caml2html: emit_gprim
| NonTail(x), Add(y, V(z)) -> Printf.fprintf oc "\tadd\t%s, %s, %s\n" (reg x) (reg y) (reg z)
| NonTail(x), Add(y, C(z)) -> Printf.fprintf oc "\taddi\t%s, %s, %d\n" (reg x) (reg y) z
| NonTail(x), Sub(y, V(z)) -> Printf.fprintf oc "\tsub\t%s, %s, %s\n" (reg x) (reg y) (reg z)
- | NonTail(x), Sub(y, C(z)) -> Printf.fprintf oc "\tsubi\t%s, %s, %d\n" (reg x) (reg y) z
+ | NonTail(x), Sub(y, C(z)) -> Printf.fprintf oc "\tsub %s, %s, %d\n" (reg x) (reg y) z
| NonTail(x), Slw(y, V(z)) -> Printf.fprintf oc "\tslw\t%s, %s, %s\n" (reg x) (reg y) (reg z)
| NonTail(x), Slw(y, C(z)) -> Printf.fprintf oc "\tslwi\t%s, %s, %d\n" (reg x) (reg y) z
| NonTail(x), Lwz(y, V(z)) -> Printf.fprintf oc "\tlwzx\t%s, %s, %s\n" (reg x) (reg y) (reg z)
@@ -117,36 +117,36 @@ and g' oc = function (* 各命令のアセンブリ生成 (caml2html: emit_gprim
(* 末尾だったら計算結果を第一レジスタにセットしてリターン (caml2html: emit_tailret) *)
| Tail, (Nop | Stw _ | Stfd _ | Comment _ | Save _ as exp) ->
g' oc (NonTail(Id.gentmp Type.Unit), exp);
- Printf.fprintf oc "\tblr\n";
+ Printf.fprintf oc "\tret\n";
| Tail, (Li _ | SetL _ | Mr _ | Neg _ | Add _ | Sub _ | Slw _ | Lwz _ as exp) ->
g' oc (NonTail(regs.(0)), exp);
- Printf.fprintf oc "\tblr\n";
+ Printf.fprintf oc "\tret\n";
| Tail, (FLi _ | FMr _ | FNeg _ | FAdd _ | FSub _ | FMul _ | FDiv _ | Lfd _ as exp) ->
g' oc (NonTail(fregs.(0)), exp);
- Printf.fprintf oc "\tblr\n";
+ Printf.fprintf oc "\tret\n";
| Tail, (Restore(x) as exp) ->
(match locate x with
| i -> g' oc (NonTail(regs.(0)), exp) | i; j when i + 1 = j -> g' oc (NonTail(fregs.(0)), exp) | _ -> assert false);
- Printf.fprintf oc "\tblr\n";
+ Printf.fprintf oc "\tret\n";
| Tail, IfEq(x, V(y), e1, e2) ->
- Printf.fprintf oc "\tcmpw\tcr7, %s, %s\n" (reg x) (reg y);
+ Printf.fprintf oc "\tcmp %s, %s\n" (reg x) (reg y);
g'_tail_if oc e1 e2 "beq" "bne"
| Tail, IfEq(x, C(y), e1, e2) ->
- Printf.fprintf oc "\tcmpwi\tcr7, %s, %d\n" (reg x) y;
+ Printf.fprintf oc "\tcmp %s, %d\n" (reg x) y;
g'_tail_if oc e1 e2 "beq" "bne"
| Tail, IfLE(x, V(y), e1, e2) ->
- Printf.fprintf oc "\tcmpw\tcr7, %s, %s\n" (reg x) (reg y);
+ Printf.fprintf oc "\tcmp %s, %s\n" (reg x) (reg y);
g'_tail_if oc e1 e2 "ble" "bgt"
| Tail, IfLE(x, C(y), e1, e2) ->
- Printf.fprintf oc "\tcmpwi\tcr7, %s, %d\n" (reg x) y;
+ Printf.fprintf oc "\tcmp %s, %d\n" (reg x) y;
g'_tail_if oc e1 e2 "ble" "bgt"
| Tail, IfGE(x, V(y), e1, e2) ->
- Printf.fprintf oc "\tcmpw\tcr7, %s, %s\n" (reg x) (reg y);
+ Printf.fprintf oc "\tcmp %s, %s\n" (reg x) (reg y);
g'_tail_if oc e1 e2 "bge" "blt"
| Tail, IfGE(x, C(y), e1, e2) ->
- Printf.fprintf oc "\tcmpwi\tcr7, %s, %d\n" (reg x) y;
+ Printf.fprintf oc "\tcmp %s, %d\n" (reg x) y;
g'_tail_if oc e1 e2 "bge" "blt"
| Tail, IfFEq(x, y, e1, e2) ->
Printf.fprintf oc "\tfcmpu\tcr7, %s, %s\n" (reg x) (reg y);
@@ -155,22 +155,22 @@ and g' oc = function (* 各命令のアセンブリ生成 (caml2html: emit_gprim
Printf.fprintf oc "\tfcmpu\tcr7, %s, %s\n" (reg x) (reg y);
g'_tail_if oc e1 e2 "ble" "bgt"
| NonTail(z), IfEq(x, V(y), e1, e2) ->
- Printf.fprintf oc "\tcmpw\tcr7, %s, %s\n" (reg x) (reg y);
+ Printf.fprintf oc "\tcmp %s, %s\n" (reg x) (reg y);
g'_non_tail_if oc (NonTail(z)) e1 e2 "beq" "bne"
| NonTail(z), IfEq(x, C(y), e1, e2) ->
- Printf.fprintf oc "\tcmpwi\tcr7, %s, %d\n" (reg x) y;
+ Printf.fprintf oc "\tcmp %s, %d\n" (reg x) y;
g'_non_tail_if oc (NonTail(z)) e1 e2 "beq" "bne"
| NonTail(z), IfLE(x, V(y), e1, e2) ->
- Printf.fprintf oc "\tcmpw\tcr7, %s, %s\n" (reg x) (reg y);
+ Printf.fprintf oc "\tcmp %s, %s\n" (reg x) (reg y);
g'_non_tail_if oc (NonTail(z)) e1 e2 "ble" "bgt"
| NonTail(z), IfLE(x, C(y), e1, e2) ->
- Printf.fprintf oc "\tcmpwi\tcr7, %s, %d\n" (reg x) y;
+ Printf.fprintf oc "\tcmp %s, %d\n" (reg x) y;
g'_non_tail_if oc (NonTail(z)) e1 e2 "ble" "bgt"
| NonTail(z), IfGE(x, V(y), e1, e2) ->
- Printf.fprintf oc "\tcmpw\tcr7, %s, %s\n" (reg x) (reg y);
+ Printf.fprintf oc "\tcmp %s, %s\n" (reg x) (reg y);
g'_non_tail_if oc (NonTail(z)) e1 e2 "bge" "blt"
| NonTail(z), IfGE(x, C(y), e1, e2) ->
- Printf.fprintf oc "\tcmpwi\tcr7, %s, %d\n" (reg x) y;
+ Printf.fprintf oc "\tcmp %s, %d\n" (reg x) y;
g'_non_tail_if oc (NonTail(z)) e1 e2 "bge" "blt"
| NonTail(z), IfFEq(x, y, e1, e2) ->
Printf.fprintf oc "\tfcmpu\tcr7, %s, %s\n" (reg x) (reg y);
@@ -220,7 +220,7 @@ and g' oc = function (* 各命令のアセンブリ生成 (caml2html: emit_gprim
Printf.fprintf oc "\tmov lr, %s\n" (reg reg_tmp)
and g'_tail_if oc e1 e2 b bn =
let b_else = Id.genid (b ^ "_else") in
- Printf.fprintf oc "\t%s\tcr7, %s\n" bn b_else;
+ Printf.fprintf oc "\t%s %s\n" bn b_else;
let stackset_back = !stackset in
g oc (Tail, e1);
Printf.fprintf oc "%s:\n" b_else;
@@ -229,7 +229,7 @@ and g'_tail_if oc e1 e2 b bn =
and g'_non_tail_if oc dest e1 e2 b bn =
let b_else = Id.genid (b ^ "_else") in
let b_cont = Id.genid (b ^ "_cont") in
- Printf.fprintf oc "\t%s\tcr7, %s\n" bn b_else;
+ Printf.fprintf oc "\t%s %s\n" bn b_else;
let stackset_back = !stackset in
g oc (dest, e1);
let stackset1 = !stackset in
@@ -247,7 +247,7 @@ and g'_args oc x_reg_cl ys zs =
(0, x_reg_cl)
ys in
List.iter
- (fun (y, r) -> Printf.fprintf oc "\tmr\t%s, %s\n" (reg r) (reg y))
+ (fun (y, r) -> Printf.fprintf oc "\tmov %s, %s\n" (reg r) (reg y))
(shuffle reg_sw yrs);
let (d, zfrs) =
List.fold_left
以下のコマンドでコンパイル・実行する。832040 が出力されればOK
code:sh
$ make clean test/fib
$ ./test/fib
sp = 0x16bce2ef8, hp = 0x130008000
832040
実際にOCamlで動かして結果を確認することもできる。
code:sh
$ ocaml test/fib.ml
832040
(test/ack.ml対応)
code:diff
diff --git a/AArch64/emit.ml b/AArch64/emit.ml
index 266db34..308b7c2 100644
--- a/AArch64/emit.ml
+++ b/AArch64/emit.ml
@@ -79,7 +79,7 @@ and g' oc = function (* 各命令のアセンブリ生成 (caml2html: emit_gprim
| NonTail(x), Mr(y) -> Printf.fprintf oc "\tmr\t%s, %s\n" (reg x) (reg y)
| NonTail(x), Neg(y) -> Printf.fprintf oc "\tneg\t%s, %s\n" (reg x) (reg y)
| NonTail(x), Add(y, V(z)) -> Printf.fprintf oc "\tadd\t%s, %s, %s\n" (reg x) (reg y) (reg z)
- | NonTail(x), Add(y, C(z)) -> Printf.fprintf oc "\taddi\t%s, %s, %d\n" (reg x) (reg y) z
+ | NonTail(x), Add(y, C(z)) -> Printf.fprintf oc "\tadd %s, %s, %d\n" (reg x) (reg y) z
| NonTail(x), Sub(y, V(z)) -> Printf.fprintf oc "\tsub\t%s, %s, %s\n" (reg x) (reg y) (reg z)
| NonTail(x), Sub(y, C(z)) -> Printf.fprintf oc "\tsub %s, %s, %d\n" (reg x) (reg y) z
| NonTail(x), Slw(y, V(z)) -> Printf.fprintf oc "\tslw\t%s, %s, %s\n" (reg x) (reg y) (reg z)
@@ -213,7 +213,7 @@ and g' oc = function (* 各命令のアセンブリ生成 (caml2html: emit_gprim
Printf.fprintf oc "\tsub %s, %s, %d\n" (reg reg_sp) (reg reg_sp) ss;
Printf.fprintf oc "\tldr %s, %s, %d\n" (reg reg_tmp) (reg reg_sp) (ss - 8); if List.mem a allregs && a <> regs.(0) then
- Printf.fprintf oc "\tmr\t%s, %s\n" (reg a) (reg regs.(0))
+ Printf.fprintf oc "\tmov %s, %s\n" (reg a) (reg regs.(0))
else if List.mem a allfregs && a <> fregs.(0) then
Printf.fprintf oc "\tfmr\t%s, %s\n" (reg a) (reg fregs.(0));
(* lrをスタックから復元 *)
(gcd.ml対応)
code:diff
diff --git a/AArch64/emit.ml b/AArch64/emit.ml
index 308b7c2..961ae88 100644
--- a/AArch64/emit.ml
+++ b/AArch64/emit.ml
@@ -62,13 +62,16 @@ and g' oc = function (* 各命令のアセンブリ生成 (caml2html: emit_gprim
(* 末尾でなかったら計算結果をdestにセット (caml2html: emit_nontail) *)
| NonTail(_), Nop -> ()
| NonTail(x), Li(i) when -32768 <= i && i < 32768 -> Printf.fprintf oc "\tmov %s, %d\n" (reg x) i
- (* TODO: こちらは後で実装する *)
| NonTail(x), Li(i) ->
- let n = i lsr 16 in
- let m = i lxor (n lsl 16) in
- let r = reg x in
- Printf.fprintf oc "\tlis\t%s, %d\n" r n;
- Printf.fprintf oc "\tori\t%s, %s, %d\n" r r m
+ (* 16ビットずつに区切って定数を読み込む *)
+ let a = i land 0xffff in
+ let b = (i lsr 16) land 0xffff in
+ let c = (i lsr 32) land 0xffff in
+ let d = (i lsr 48) land 0xffff in
+ Printf.fprintf oc "\tmov %s, %d\n" (reg x) a;
+ Printf.fprintf oc "\tmovk %s, %d, lsl 16\n" (reg x) b;
+ Printf.fprintf oc "\tmovk %s, %d, lsl 32\n" (reg x) c;
+ Printf.fprintf oc "\tmovk %s, %d, lsl 48\n" (reg x) d
| NonTail(x), FLi(Id.L(l)) ->
let s = load_label (reg reg_tmp) l in
Printf.fprintf oc "%s\tlfd\t%s, 0(%s)\n" s (reg x) (reg reg_tmp)
@@ -76,7 +79,7 @@ and g' oc = function (* 各命令のアセンブリ生成 (caml2html: emit_gprim
let s = load_label x y in
Printf.fprintf oc "%s" s
| NonTail(x), Mr(y) when x = y -> ()
- | NonTail(x), Mr(y) -> Printf.fprintf oc "\tmr\t%s, %s\n" (reg x) (reg y)
+ | NonTail(x), Mr(y) -> Printf.fprintf oc "\tmov %s, %s\n" (reg x) (reg y)
| NonTail(x), Neg(y) -> Printf.fprintf oc "\tneg\t%s, %s\n" (reg x) (reg y)
| NonTail(x), Add(y, V(z)) -> Printf.fprintf oc "\tadd\t%s, %s, %s\n" (reg x) (reg y) (reg z)
| NonTail(x), Add(y, C(z)) -> Printf.fprintf oc "\tadd %s, %s, %d\n" (reg x) (reg y) z
クロージャ対応
クロージャのAArch64対応を行う。test/adder.ml や test/even-odd.ml などでクロージャを利用しているので、そちらで動作確認を行う。
code:diff
diff --git a/AArch64/emit.ml b/AArch64/emit.ml
index 961ae88..9a15a22 100644
--- a/AArch64/emit.ml
+++ b/AArch64/emit.ml
@@ -33,9 +33,7 @@ let reg r =
let load_label r label =
let r' = reg r in
- Printf.sprintf
- "\tlis\t%s, ha16(%s)\n\taddi\t%s, %s, lo16(%s)\n"
- r' label r' r' label
+ Printf.sprintf "\tadr %s, %s\n" r' label
(* 関数呼び出しのために引数を並べ替える(register shuffling) (caml2html: emit_shuffle) *)
let rec shuffle sw xys =
@@ -88,9 +86,9 @@ and g' oc = function (* 各命令のアセンブリ生成 (caml2html: emit_gprim
| NonTail(x), Slw(y, V(z)) -> Printf.fprintf oc "\tslw\t%s, %s, %s\n" (reg x) (reg y) (reg z)
| NonTail(x), Slw(y, C(z)) -> Printf.fprintf oc "\tslwi\t%s, %s, %d\n" (reg x) (reg y) z
| NonTail(x), Lwz(y, V(z)) -> Printf.fprintf oc "\tlwzx\t%s, %s, %s\n" (reg x) (reg y) (reg z)
- | NonTail(x), Lwz(y, C(z)) -> Printf.fprintf oc "\tlwz\t%s, %d(%s)\n" (reg x) z (reg y)
+ | NonTail(x), Lwz(y, C(z)) -> Printf.fprintf oc "\tldr %s, %s, %d\n" (reg x) (reg y) z | NonTail(_), Stw(x, y, V(z)) -> Printf.fprintf oc "\tstwx\t%s, %s, %s\n" (reg x) (reg y) (reg z)
- | NonTail(_), Stw(x, y, C(z)) -> Printf.fprintf oc "\tstw\t%s, %d(%s)\n" (reg x) z (reg y)
+ | NonTail(_), Stw(x, y, C(z)) -> Printf.fprintf oc "\tstr %s, %s, %d\n" (reg x) (reg y) z | NonTail(x), FMr(y) when x = y -> ()
| NonTail(x), FMr(y) -> Printf.fprintf oc "\tfmr\t%s, %s\n" (reg x) (reg y)
| NonTail(x), FNeg(y) -> Printf.fprintf oc "\tfneg\t%s, %s\n" (reg x) (reg y)
@@ -184,27 +182,42 @@ and g' oc = function (* 各命令のアセンブリ生成 (caml2html: emit_gprim
(* 関数呼び出しの仮想命令の実装 (caml2html: emit_call) *)
| Tail, CallCls(x, ys, zs) -> (* 末尾呼び出し (caml2html: emit_tailcall) *)
- Printf.fprintf oc "\tlwz\t%s, 0(%s)\n" (reg reg_sw) (reg reg_cl);
- Printf.fprintf oc "\tmtctr\t%s\n\tbctr\n" (reg reg_sw);
+ (* クロージャを呼び出し *)
+ Printf.fprintf oc "\tldr %s, %s, 0\n" (reg reg_sw) (reg reg_cl); + Printf.fprintf oc "\tbr %s\n" (reg reg_sw)
+ (* Printf.fprintf oc "\tlwz\t%s, 0(%s)\n" (reg reg_sw) (reg reg_cl);
+ Printf.fprintf oc "\tmtctr\t%s\n\tbctr\n" (reg reg_sw); *)
| Tail, CallDir(Id.L(x), ys, zs) -> (* 末尾呼び出し *)
g'_args oc [] ys zs;
Printf.fprintf oc "\tb\t%s\n" x
| NonTail(a), CallCls(x, ys, zs) ->
- Printf.fprintf oc "\tmflr\t%s\n" (reg reg_tmp);
+ (* Printf.fprintf oc "\tmflr\t%s\n" (reg reg_tmp); *)
let ss = stacksize () in
- Printf.fprintf oc "\tstw\t%s, %d(%s)\n" (reg reg_tmp) (ss - 4) (reg reg_sp);
- Printf.fprintf oc "\taddi\t%s, %s, %d\n" (reg reg_sp) (reg reg_sp) ss;
+ (* lrをスタックへ退避 *)
+ Printf.fprintf oc "\tmov %s, lr\n" (reg reg_tmp);
+ Printf.fprintf oc "\tstr %s, %s, %d\n" (reg reg_tmp) (reg reg_sp) (ss - 8); + Printf.fprintf oc "\tadd %s, %s, %d\n" (reg reg_sp) (reg reg_sp) ss;
+ (* クロージャを呼び出し *)
+ Printf.fprintf oc "\tldr %s, %s, 0\n" (reg reg_tmp) (reg reg_cl); + Printf.fprintf oc "\tblr %s\n" (reg reg_tmp);
+ Printf.fprintf oc "\tsub %s, %s, %d\n" (reg reg_sp) (reg reg_sp) ss;
+ Printf.fprintf oc "\tldr %s, %s, %d\n" (reg reg_tmp) (reg reg_sp) (ss - 8); + (* Printf.fprintf oc "\tstw\t%s, %d(%s)\n" (reg reg_tmp) (ss - 4) (reg reg_sp);
+ Printf.fprintf oc "\t@@@addi\t%s, %s, %d\n" (reg reg_sp) (reg reg_sp) ss;
Printf.fprintf oc "\tlwz\t%s, 0(%s)\n" (reg reg_tmp) (reg reg_cl);
Printf.fprintf oc "\tmtctr\t%s\n" (reg reg_tmp);
Printf.fprintf oc "\tbctrl\n";
- Printf.fprintf oc "\tsubi\t%s, %s, %d\n" (reg reg_sp) (reg reg_sp) ss;
- Printf.fprintf oc "\tlwz\t%s, %d(%s)\n" (reg reg_tmp) (ss - 4) (reg reg_sp);
+ Printf.fprintf oc "\t@@@subi\t%s, %s, %d\n" (reg reg_sp) (reg reg_sp) ss;
+ Printf.fprintf oc "\tlwz\t%s, %d(%s)\n" (reg reg_tmp) (ss - 4) (reg reg_sp); *)
if List.mem a allregs && a <> regs.(0) then
Printf.fprintf oc "\tmr\t%s, %s\n" (reg a) (reg regs.(0))
else if List.mem a allfregs && a <> fregs.(0) then
Printf.fprintf oc "\tfmr\t%s, %s\n" (reg a) (reg fregs.(0));
- Printf.fprintf oc "\tmtlr\t%s\n" (reg reg_tmp)
+ (* lrをスタックから復元 *)
+ Printf.fprintf oc "\tmov lr, %s\n" (reg reg_tmp)
+ (* Printf.fprintf oc "\tmtlr\t%s\n" (reg reg_tmp) *)
| (NonTail(a), CallDir(Id.L(x), ys, zs)) ->
g'_args oc [] ys zs;
let ss = stacksize () in
diff --git a/AArch64/virtual.ml b/AArch64/virtual.ml
index 3752289..671fe1a 100644
--- a/AArch64/virtual.ml
+++ b/AArch64/virtual.ml
@@ -29,7 +29,8 @@ let expand xts ini addf addi =
let offset = align offset in
(offset + 8, addf x offset acc))
(fun (offset, acc) x t ->
- (offset + 4, addi x t offset acc))
+ (* NOTE: 64ビットなので4バイトから8バイトにする *)
+ (offset + 8, addi x t offset acc))
let rec g env = function (* 式の仮想マシンコード生成 (caml2html: virtual_g) *)
| Closure.Unit -> Ans(Nop)
@@ -78,7 +79,8 @@ let rec g env = function (* 式の仮想マシンコード生成 (caml2html: vir
let offset, store_fv =
expand
(List.map (fun y -> (y, M.find y env)) ys)
- (4, e2')
+ (* NOTE: 64ビットなので4バイトから8バイトにする *)
+ (8, e2')
(fun y offset store_fv -> seq(Stfd(y, x, C(offset)), store_fv))
(fun y _ offset store_fv -> seq(Stw(y, x, C(offset)), store_fv)) in
Let((x, t), Mr(reg_hp),
@@ -147,7 +149,8 @@ let h { Closure.name = (Id.L(x), t); Closure.args = yts; Closure.formal_fv = zts
let (offset, load) =
expand
zts
- (4, g (M.add x t (M.add_list yts (M.add_list zts M.empty))) e)
+ (* NOTE: 64ビットなので4バイトから8バイトにする *)
+ (8, g (M.add x t (M.add_list yts (M.add_list zts M.empty))) e)
(fun z offset load -> fletd(z, Lfd(x, C(offset)), load))
(fun z t offset load -> Let((z, t), Lwz(x, C(offset)), load)) in
match t with
Array.make対応
MinCamlで Array.make を実行すると、内部では libmincaml.S の min_caml_create_array が呼び出される。
libmincaml.S には min_caml_print_int と min_caml_print_newline しか定義されてないので、min_caml_create_array を新たに定義する。
Arrayのテストコードはこちら。
code:test/array-test.ml
let a = Array.make 3 10 in
let b = Array.make 2 100 in
print_int a.(0); print_newline ();
print_int a.(1); print_newline ();
print_int a.(2); print_newline ();
print_int b.(0); print_newline ();
print_int b.(1); print_newline ();
a.(0) <- a.(0) + 10;
a.(1) <- a.(1) + 20;
a.(2) <- a.(2) + 30;
print_int a.(0); print_newline ();
print_int a.(1); print_newline ();
print_int a.(2); print_newline ();
print_int b.(0); print_newline ();
print_int b.(1); print_newline ()
Arrayの実装はこちら。
code:diff
diff --git a/AArch64/libmincaml.c b/AArch64/libmincaml.c
index 8584611..d996957 100644
--- a/AArch64/libmincaml.c
+++ b/AArch64/libmincaml.c
@@ -3,6 +3,7 @@
// NOTE: コンパイル後のシンボルのプリフィックスに _ がつくのを避ける
void min_caml_print_int(long n) asm("min_caml_print_int");
void min_caml_print_newline() asm("min_caml_print_newline");
+long* min_caml_create_array(long number_of_element, long init_value) asm("min_caml_create_array");
void min_caml_print_int(long n) {
printf("%ld", n);
@@ -11,3 +12,24 @@ void min_caml_print_int(long n) {
void min_caml_print_newline() {
printf("\n");
}
+
+long* min_caml_create_array(long number_of_element, long init_value) {
+ long *heap_ptr;
+
+ // x27 に格納されたヒープのアドレスを heap_ptr へ書き出す
+ asm volatile ("mov %0, x27" : "=r"(heap_ptr));
+
+ // Array の先頭アドレスを取得
+ long *array_ptr = heap_ptr;
+
+ for (long i = 0l; i < number_of_element; i++) {
+ // Array へ書き込んだ後、ヒープの先頭アドレスを8バイト進める
+ *heap_ptr = init_value;
+ heap_ptr += 1;
+ }
+
+ // ヒープの先頭アドレスを x27 に書き戻す
+ asm volatile ("mov x27, %0" : : "r"(heap_ptr));
+
+ return array_ptr;
+}
diff --git a/AArch64/virtual.ml b/AArch64/virtual.ml
index 671fe1a..a61e8a0 100644
--- a/AArch64/virtual.ml
+++ b/AArch64/virtual.ml
@@ -124,10 +124,12 @@ let rec g env = function (* 式の仮想マシンコード生成 (caml2html: vir
(match M.find x env with
| Type.Array(Type.Unit) -> Ans(Nop)
| Type.Array(Type.Float) ->
+ (* float の Array は1要素で8バイトなので、渡されたインデックス値を8倍したものをオフセットとする *)
Let((offset, Type.Int), Slw(y, C(3)),
Ans(Lfd(x, V(offset))))
| Type.Array(_) ->
- Let((offset, Type.Int), Slw(y, C(2)),
+ (* int の Array は1要素で8バイトなので、渡されたインデックス値を8倍したものをオフセットとする *)
+ Let((offset, Type.Int), Slw(y, C(3)),
Ans(Lwz(x, V(offset))))
| _ -> assert false)
| Closure.Put(x, y, z) ->
@@ -135,10 +137,12 @@ let rec g env = function (* 式の仮想マシンコード生成 (caml2html: vir
(match M.find x env with
| Type.Array(Type.Unit) -> Ans(Nop)
| Type.Array(Type.Float) ->
+ (* float の Array は1要素で8バイトなので、渡されたインデックス値を8倍したものをオフセットとする *)
Let((offset, Type.Int), Slw(y, C(3)),
Ans(Stfd(z, x, V(offset))))
| Type.Array(_) ->
- Let((offset, Type.Int), Slw(y, C(2)),
+ (* int の Array は1要素で8バイトなので、渡されたインデックス値を8倍したものをオフセットとする *)
+ Let((offset, Type.Int), Slw(y, C(3)),
Ans(Stw(z, x, V(offset))))
| _ -> assert false)
| Closure.ExtArray(Id.L(x)) -> Ans(SetL(Id.L("min_caml_" ^ x)))
ビルドして実行する。いい感じに動いてそう。
code:sh
$ gcc -S -o AArch64/libmincaml.S AArch64/libmincaml.c && make clean test/array-test && ./test/array-test
(省略)
sp = 0x16d602988, hp = 0x128008000
10
10
10
100
100
20
30
40
100
100
浮動小数点数対応
これまでは整数しか対応していなかったので、浮動小数点数を扱えるように手を入れる。
まずは以下のテストコードを動かすようにする。
code:test/non-tail-if.ml
let x = truncate 1.23 in
let y = truncate 4.56 in
let z = truncate (-.7.89) in
print_int
((if z < 0 then y else x) +
(if x > 0 then z else y) +
(if y < 0 then x else z))
以下の修正を行い、
code:diff
diff --git a/AArch64/asm.ml b/AArch64/asm.ml
index 12b71f7..0a45fe4 100644
--- a/AArch64/asm.ml
+++ b/AArch64/asm.ml
@@ -50,7 +50,7 @@ let regs = (* Array.init 27 (fun i -> Printf.sprintf "_R_%d" i) *)
[| "%x0"; "%x1"; "%x2"; "%x3"; "%x4"; "%x5"; "%x6"; "%x7"; "%x8"; "%x9"; "%x10";
"%x11"; "%x12"; "%x13"; "%x14"; "%x15"; "%x16"; "%x17"; "%x18"; "%x19"; "%x20";
"%x21"; "%x22"; "%x23"; "%x24"; "%x25" |]
-let fregs = Array.init 32 (fun i -> Printf.sprintf "%%f%d" i)
+let fregs = Array.init 32 (fun i -> Printf.sprintf "%%d%d" i)
let allregs = Array.to_list regs
let allfregs = Array.to_list fregs
let reg_cl = regs.(Array.length regs - 1) (* closure address (caml2html: sparcasm_regcl) *)
diff --git a/AArch64/emit.ml b/AArch64/emit.ml
index ecfb282..915381a 100644
--- a/AArch64/emit.ml
+++ b/AArch64/emit.ml
@@ -71,8 +71,9 @@ and g' oc = function (* 各命令のアセンブリ生成 (caml2html: emit_gprim
Printf.fprintf oc "\tmovk %s, %d, lsl 32\n" (reg x) c;
Printf.fprintf oc "\tmovk %s, %d, lsl 48\n" (reg x) d
| NonTail(x), FLi(Id.L(l)) ->
- let s = load_label (reg reg_tmp) l in
- Printf.fprintf oc "%s\tlfd\t%s, 0(%s)\n" s (reg x) (reg reg_tmp)
+ (* ラベル l に格納された浮動小数点数をレジスタへロードする *)
+ Printf.fprintf oc "\tadrp %s, %s@PAGE\n" (reg reg_tmp) l;
+ Printf.fprintf oc "\tldr %s, %s, %s@PAGEOFF\n" (reg x) (reg reg_tmp) l | NonTail(x), SetL(Id.L(y)) ->
let s = load_label x y in
Printf.fprintf oc "%s" s
diff --git a/AArch64/libmincaml.S b/AArch64/libmincaml.S
index a9a0a87..3885e2f 100644
--- a/AArch64/libmincaml.S
+++ b/AArch64/libmincaml.S
@@ -84,6 +84,20 @@ LBB2_4:
ret
+ .cfi_endproc
+ ; -- End function
+ .globl min_caml_truncate ; -- Begin function min_caml_truncate
+ .p2align 2
+min_caml_truncate: ; @"\01min_caml_truncate"
+ .cfi_startproc
+; %bb.0:
+ .cfi_def_cfa_offset 16
+ fcvtzs x0, d0
+ ret
.cfi_endproc
; -- End function
.section __TEXT,__cstring,cstring_literals
diff --git a/AArch64/libmincaml.c b/AArch64/libmincaml.c
index d996957..8a38139 100644
--- a/AArch64/libmincaml.c
+++ b/AArch64/libmincaml.c
@@ -4,6 +4,7 @@
void min_caml_print_int(long n) asm("min_caml_print_int");
void min_caml_print_newline() asm("min_caml_print_newline");
long* min_caml_create_array(long number_of_element, long init_value) asm("min_caml_create_array");
+long min_caml_truncate() asm("min_caml_truncate");
void min_caml_print_int(long n) {
printf("%ld", n);
@@ -33,3 +34,8 @@ long* min_caml_create_array(long number_of_element, long init_value) {
return array_ptr;
}
+
+// truncate
+long min_caml_truncate(double d) {
+ return (long)d;
+}
code:sh
$ gcc -S -o AArch64/libmincaml.S AArch64/libmincaml.c && make clean test/non-tail-if && ./test/non-tail-if
...
(省略)
...
-10
test/inprod対応
code:diff
diff --git a/AArch64/emit.ml b/AArch64/emit.ml
index 915381a..8964488 100644
--- a/AArch64/emit.ml
+++ b/AArch64/emit.ml
@@ -98,9 +98,9 @@ and g' oc = function (* 各命令のアセンブリ生成 (caml2html: emit_gprim
| NonTail(x), FMul(y, z) -> Printf.fprintf oc "\tfmul\t%s, %s, %s\n" (reg x) (reg y) (reg z)
| NonTail(x), FDiv(y, z) -> Printf.fprintf oc "\tfdiv\t%s, %s, %s\n" (reg x) (reg y) (reg z)
| NonTail(x), Lfd(y, V(z)) -> Printf.fprintf oc "\tlfdx\t%s, %s, %s\n" (reg x) (reg y) (reg z)
- | NonTail(x), Lfd(y, C(z)) -> Printf.fprintf oc "\tlfd\t%s, %d(%s)\n" (reg x) z (reg y)
+ | NonTail(x), Lfd(y, C(z)) -> Printf.fprintf oc "\tldr %s, %s, %d\n" (reg x) (reg y) z | NonTail(_), Stfd(x, y, V(z)) -> Printf.fprintf oc "\tstfdx\t%s, %s, %s\n" (reg x) (reg y) (reg z)
- | NonTail(_), Stfd(x, y, C(z)) -> Printf.fprintf oc "\tstfd\t%s, %d(%s)\n" (reg x) z (reg y)
+ | NonTail(_), Stfd(x, y, C(z)) -> Printf.fprintf oc "\tstr %s, %s, %d\n" (reg x) (reg y) z | NonTail(_), Comment(s) -> Printf.fprintf oc "#\t%s\n" s
(* 退避の仮想命令の実装 (caml2html: emit_save) *)
| NonTail(_), Save(x, y) when List.mem x allregs && not (S.mem y !stackset) ->
@@ -108,14 +108,14 @@ and g' oc = function (* 各命令のアセンブリ生成 (caml2html: emit_gprim
Printf.fprintf oc "\tstr %s, %s, %d\n" (reg x) (reg reg_sp) (offset y) | NonTail(_), Save(x, y) when List.mem x allfregs && not (S.mem y !stackset) ->
savef y;
- Printf.fprintf oc "\tstfd\t%s, %d(%s)\n" (reg x) (offset y) (reg reg_sp)
+ Printf.fprintf oc "\tstr %s, %s, %d\n" (reg x) (reg reg_sp) (offset y) | NonTail(_), Save(x, y) -> assert (S.mem y !stackset); ()
(* 復帰の仮想命令の実装 (caml2html: emit_restore) *)
| NonTail(x), Restore(y) when List.mem x allregs ->
Printf.fprintf oc "\tldr %s, %s, %d\n" (reg x) (reg reg_sp) (offset y) | NonTail(x), Restore(y) ->
assert (List.mem x allfregs);
- Printf.fprintf oc "\tlfd\t%s, %d(%s)\n" (reg x) (offset y) (reg reg_sp)
+ Printf.fprintf oc "\tldr %s, %s, %d\n" (reg x) (reg reg_sp) (offset y) (* 末尾だったら計算結果を第一レジスタにセットしてリターン (caml2html: emit_tailret) *)
| Tail, (Nop | Stw _ | Stfd _ | Comment _ | Save _ as exp) ->
g' oc (NonTail(Id.gentmp Type.Unit), exp);
実行する。
code:sh
$ ./test/inprod
sp = 0x16f64eeb8, hp = 0x118008000
32000000
Array.makeの浮動小数点数対応
整数での Array.make は対応したが浮動小数点数での Array.make はまだ未対応なので実装する。
整数で Array.make した場合は min_caml_create_array が呼び出されるが、浮動小数点数で Array.make した場合は min_caml_create_float_array が呼び出されるので、libmincaml.c へ min_caml_create_float_array を新たに定義する。
Array.make の浮動小数点数対応のテストコードはこちら。
code:test/array-test2.ml
let a = Array.make 3 3.141 in
let b = Array.make 100 2.236 in
print_int (truncate a.(0)); print_newline ();
print_int (truncate a.(1)); print_newline ();
print_int (truncate a.(2)); print_newline ();
print_int (truncate b.(0)); print_newline ();
print_int (truncate b.(1)); print_newline ();
print_int (truncate b.(99)); print_newline ();
a.(0) <- a.(0) +. 10.0;
a.(1) <- a.(1) +. 20.0;
a.(2) <- a.(2) +. 30.0;
print_int (truncate a.(0)); print_newline ();
print_int (truncate a.(1)); print_newline ();
print_int (truncate a.(2)); print_newline ();
print_int (truncate b.(0)); print_newline ();
print_int (truncate b.(1)); print_newline ();
print_int (truncate b.(99)); print_newline ()
min_caml_create_float_array の実装はこちら。
code:diff
diff --git a/AArch64/libmincaml.c b/AArch64/libmincaml.c
index 8a38139..365580c 100644
--- a/AArch64/libmincaml.c
+++ b/AArch64/libmincaml.c
@@ -4,6 +4,7 @@
void min_caml_print_int(long n) asm("min_caml_print_int");
void min_caml_print_newline() asm("min_caml_print_newline");
long* min_caml_create_array(long number_of_element, long init_value) asm("min_caml_create_array");
+double* min_caml_create_float_array(long number_of_element, double float_value) asm("min_caml_create_float_array");
long min_caml_truncate() asm("min_caml_truncate");
void min_caml_print_int(long n) {
@@ -35,7 +36,29 @@ long* min_caml_create_array(long number_of_element, long init_value) {
return array_ptr;
}
+double* min_caml_create_float_array(long number_of_element, double float_value) {
+ double *heap_ptr;
+
+ // x27 に格納されたヒープのアドレスを heap_ptr へ書き出す
+ asm volatile ("mov %0, x27" : "=r"(heap_ptr));
+
+ // Array の先頭アドレスを取得
+ long *array_ptr = heap_ptr;
+
+ for (long i = 0l; i < number_of_element; i++) {
+ // Array へ書き込んだ後、ヒープの先頭アドレスを8バイト進める
+ *heap_ptr = float_value;
+ heap_ptr += 1;
+ }
+
+ // ヒープの先頭アドレスを x27 に書き戻す
+ asm volatile ("mov x27, %0" : : "r"(heap_ptr));
+
+ return array_ptr;
+}
+
// truncate
long min_caml_truncate(double d) {
return (long)d;
}
実行してみる。
code:sh
$ gcc -S -o AArch64/libmincaml.S AArch64/libmincaml.c && make clean test/array-test2 && ./test/array-test2
...
(省略)
...
sp = 0x16ad56e98, hp = 0x148008000
3
3
3
2
2
2
13
23
33
2
2
2
test/inprod-rec対応
浮動小数点数の定数のかけ算 & 配列操作を行う test/inprod-rec.ml を動くようにする。
code:test/inprod-rec.ml
let rec inprod v1 v2 i =
if i < 0 then 0.0 else
v1.(i) *. v2.(i) +. inprod v1 v2 (i - 1) in
let v1 = Array.make 3 1.23 in
let v2 = Array.make 3 4.56 in
print_int (truncate (1000000. *. inprod v1 v2 2))
以下を実装。
左シフト(Slw)の定数バージョン
変数からの浮動小数点数のロード
code:diff
diff --git a/AArch64/emit.ml b/AArch64/emit.ml
index 8964488..744cace 100644
--- a/AArch64/emit.ml
+++ b/AArch64/emit.ml
@@ -85,7 +85,7 @@ and g' oc = function (* 各命令のアセンブリ生成 (caml2html: emit_gprim
| NonTail(x), Sub(y, V(z)) -> Printf.fprintf oc "\tsub\t%s, %s, %s\n" (reg x) (reg y) (reg z)
| NonTail(x), Sub(y, C(z)) -> Printf.fprintf oc "\tsub %s, %s, %d\n" (reg x) (reg y) z
| NonTail(x), Slw(y, V(z)) -> Printf.fprintf oc "\tslw\t%s, %s, %s\n" (reg x) (reg y) (reg z)
- | NonTail(x), Slw(y, C(z)) -> Printf.fprintf oc "\tslwi\t%s, %s, %d\n" (reg x) (reg y) z
+ | NonTail(x), Slw(y, C(z)) -> Printf.fprintf oc "\tlsl %s, %s, %d\n" (reg x) (reg y) z
| NonTail(x), Lwz(y, V(z)) -> Printf.fprintf oc "\tlwzx\t%s, %s, %s\n" (reg x) (reg y) (reg z)
| NonTail(x), Lwz(y, C(z)) -> Printf.fprintf oc "\tldr %s, %s, %d\n" (reg x) (reg y) z | NonTail(_), Stw(x, y, V(z)) -> Printf.fprintf oc "\tstwx\t%s, %s, %s\n" (reg x) (reg y) (reg z)
@@ -97,7 +97,7 @@ and g' oc = function (* 各命令のアセンブリ生成 (caml2html: emit_gprim
| NonTail(x), FSub(y, z) -> Printf.fprintf oc "\tfsub\t%s, %s, %s\n" (reg x) (reg y) (reg z)
| NonTail(x), FMul(y, z) -> Printf.fprintf oc "\tfmul\t%s, %s, %s\n" (reg x) (reg y) (reg z)
| NonTail(x), FDiv(y, z) -> Printf.fprintf oc "\tfdiv\t%s, %s, %s\n" (reg x) (reg y) (reg z)
- | NonTail(x), Lfd(y, V(z)) -> Printf.fprintf oc "\tlfdx\t%s, %s, %s\n" (reg x) (reg y) (reg z)
+ | NonTail(x), Lfd(y, V(z)) -> Printf.fprintf oc "\tldr %s, %s, %s\n" (reg x) (reg y) (reg z) | NonTail(x), Lfd(y, C(z)) -> Printf.fprintf oc "\tldr %s, %s, %d\n" (reg x) (reg y) z | NonTail(_), Stfd(x, y, V(z)) -> Printf.fprintf oc "\tstfdx\t%s, %s, %s\n" (reg x) (reg y) (reg z)
| NonTail(_), Stfd(x, y, C(z)) -> Printf.fprintf oc "\tstr %s, %s, %d\n" (reg x) (reg y) z 動かしてみる。
code:sh
$ make clean test/inprod-rec && ./test/inprod-rec
(省略)
sp = 0x16b3b6ea8, hp = 0x138008000
16826400%
test/inprod-loop対応
test/inprod-loop.ml がビルドできないので対応する。
code:test/inprod-loop.ml
let rec inprod v1 v2 acc i =
if i < 0 then acc else
inprod v1 v2 (acc +. v1.(i) *. v2.(i)) (i - 1) in
let v1 = Array.make 3 1.23 in
let v2 = Array.make 3 4.56 in
print_int (truncate (1000000. *. inprod v1 v2 0. 2))
浮動小数点数レジスタの退避まわりでエラーが出てるので以下のように修正。
code:diff
diff --git a/AArch64/emit.ml b/AArch64/emit.ml
index 744cace..9008bc0 100644
--- a/AArch64/emit.ml
+++ b/AArch64/emit.ml
@@ -272,7 +272,7 @@ and g'_args oc x_reg_cl ys zs =
(0, [])
zs in
List.iter
- (fun (z, fr) -> Printf.fprintf oc "\tfmr\t%s, %s\n" (reg fr) (reg z))
+ (fun (z, fr) -> Printf.fprintf oc "\tfmov %s, %s\n" (reg fr) (reg z))
(shuffle reg_fsw zfrs)
let h oc { name = Id.L(x); args = _; fargs = _; body = e; ret = _ } =
動かしてみる。
code:sh
$ make clean test/inprod-loop && ./test/inprod-loop
(省略)
sp = 0x16db66e98, hp = 0x120008000
16826400
test/matmul対応
test/matmul.ml のビルドが落ちるので対応する。行列(matrix)の乗算(multiply)かな?
code:test/matmul.ml
let rec mul l m n a b c =
let rec loop1 i =
if i < 0 then () else
let rec loop2 j =
if j < 0 then () else
let rec loop3 k =
if k < 0 then () else
(c.(i).(j) <- c.(i).(j) +. a.(i).(k) *. b.(k).(j);
loop3 (k - 1)) in
loop3 (m - 1);
loop2 (j - 1) in
loop2 (n - 1);
loop1 (i - 1) in
loop1 (l - 1) in
let dummy = Array.make 0 0. in
let rec make m n =
let mat = Array.make m dummy in
let rec init i =
if i < 0 then () else
(mat.(i) <- Array.make n 0.;
init (i - 1)) in
init (m - 1);
mat in
let a = make 2 3 in
let b = make 3 2 in
let c = make 2 2 in
a.(0).(0) <- 1.; a.(0).(1) <- 2.; a.(0).(2) <- 3.;
a.(1).(0) <- 4.; a.(1).(1) <- 5.; a.(1).(2) <- 6.;
b.(0).(0) <- 7.; b.(0).(1) <- 8.;
b.(1).(0) <- 9.; b.(1).(1) <- 10.;
b.(2).(0) <- 11.; b.(2).(1) <- 12.;
mul 2 3 2 a b c;
print_int (truncate (c.(0).(0)));
print_newline ();
print_int (truncate (c.(0).(1)));
print_newline ();
print_int (truncate (c.(1).(0)));
print_newline ();
print_int (truncate (c.(1).(1)));
print_newline ()
以下を修正。
code:diff
diff --git a/AArch64/emit.ml b/AArch64/emit.ml
index 9008bc0..cbd8c5b 100644
--- a/AArch64/emit.ml
+++ b/AArch64/emit.ml
@@ -86,9 +86,9 @@ and g' oc = function (* 各命令のアセンブリ生成 (caml2html: emit_gprim
| NonTail(x), Sub(y, C(z)) -> Printf.fprintf oc "\tsub %s, %s, %d\n" (reg x) (reg y) z
| NonTail(x), Slw(y, V(z)) -> Printf.fprintf oc "\tslw\t%s, %s, %s\n" (reg x) (reg y) (reg z)
| NonTail(x), Slw(y, C(z)) -> Printf.fprintf oc "\tlsl %s, %s, %d\n" (reg x) (reg y) z
- | NonTail(x), Lwz(y, V(z)) -> Printf.fprintf oc "\tlwzx\t%s, %s, %s\n" (reg x) (reg y) (reg z)
+ | NonTail(x), Lwz(y, V(z)) -> Printf.fprintf oc "\tldr %s, %s, %s\n" (reg x) (reg y) (reg z) | NonTail(x), Lwz(y, C(z)) -> Printf.fprintf oc "\tldr %s, %s, %d\n" (reg x) (reg y) z - | NonTail(_), Stw(x, y, V(z)) -> Printf.fprintf oc "\tstwx\t%s, %s, %s\n" (reg x) (reg y) (reg z)
+ | NonTail(_), Stw(x, y, V(z)) -> Printf.fprintf oc "\tstr %s, %s, %s\n" (reg x) (reg y) (reg z) | NonTail(_), Stw(x, y, C(z)) -> Printf.fprintf oc "\tstr %s, %s, %d\n" (reg x) (reg y) z | NonTail(x), FMr(y) when x = y -> ()
| NonTail(x), FMr(y) -> Printf.fprintf oc "\tfmr\t%s, %s\n" (reg x) (reg y)
@@ -99,7 +99,7 @@ and g' oc = function (* 各命令のアセンブリ生成 (caml2html: emit_gprim
| NonTail(x), FDiv(y, z) -> Printf.fprintf oc "\tfdiv\t%s, %s, %s\n" (reg x) (reg y) (reg z)
| NonTail(x), Lfd(y, V(z)) -> Printf.fprintf oc "\tldr %s, %s, %s\n" (reg x) (reg y) (reg z) | NonTail(x), Lfd(y, C(z)) -> Printf.fprintf oc "\tldr %s, %s, %d\n" (reg x) (reg y) z - | NonTail(_), Stfd(x, y, V(z)) -> Printf.fprintf oc "\tstfdx\t%s, %s, %s\n" (reg x) (reg y) (reg z)
+ | NonTail(_), Stfd(x, y, V(z)) -> Printf.fprintf oc "\tstr %s, %s, %s\n" (reg x) (reg y) (reg z) | NonTail(_), Stfd(x, y, C(z)) -> Printf.fprintf oc "\tstr %s, %s, %d\n" (reg x) (reg y) z | NonTail(_), Comment(s) -> Printf.fprintf oc "#\t%s\n" s
(* 退避の仮想命令の実装 (caml2html: emit_save) *)
実行してみる。
code:sh
$ make clean test/matmul && ./test/matmul
(省略)
sp = 0x16f7beeb8, hp = 0x158008000
58
64
139
154
test/manyargs.mlが動かないけど、ひとまずスルー
code:diff
diff --git a/Makefile b/Makefile
index 23a02f5..84d2752 100644
--- a/Makefile
+++ b/Makefile
@@ -32,8 +32,7 @@ TESTS = print sum-tail gcd sum fib ack even-odd \
adder funcomp cls-rec cls-bug cls-bug2 cls-reg-bug \
shuffle spill spill2 spill3 join-stack join-stack2 join-stack3 \
join-reg join-reg2 non-tail-if non-tail-if2 \
-inprod inprod-rec inprod-loop matmul matmul-flat \
-manyargs
+inprod inprod-rec inprod-loop matmul matmul-flat
do_test: $(TESTS:%=test/%.cmp)
浮動小数点数の条件分岐
test ディレクトリ以下のプログラムは動くようになったものの、浮動小数点数の条件分岐がまだAArch64に対応できていないので以下のサンプルプログラムを動くようにする。
code:test/float-if.ml
let a = 1.0 in
let b = 2.0 in
let rec eq a b = a = b in
let rec le a b = a < b in
(* NonTail IfFEq *)
if a = a then
print_int 1
else
print_int 0;
if a = b then
print_int 0
else
print_int 1;
(* NonTail IfFLe *)
if a < b then
print_int 1
else
print_int 0;
if b < a then
print_int 0
else
print_int 1;
(* Tail IfFEq *)
if eq a a then
print_int 1
else
print_int 0;
if eq a b then
print_int 0
else
print_int 1;
(* Tail IfFLe *)
if le a b then
print_int 1
else
print_int 0;
if le b a then
print_int 0
else
print_int 1
以下のように修正して、
code:diff
diff --git a/AArch64/emit.ml b/AArch64/emit.ml
index cbd8c5b..715c22c 100644
--- a/AArch64/emit.ml
+++ b/AArch64/emit.ml
@@ -151,10 +151,10 @@ and g' oc = function (* 各命令のアセンブリ生成 (caml2html: emit_gprim
Printf.fprintf oc "\tcmp %s, %d\n" (reg x) y;
g'_tail_if oc e1 e2 "bge" "blt"
| Tail, IfFEq(x, y, e1, e2) ->
- Printf.fprintf oc "\tfcmpu\tcr7, %s, %s\n" (reg x) (reg y);
+ Printf.fprintf oc "\tfcmp %s, %s\n" (reg x) (reg y);
g'_tail_if oc e1 e2 "beq" "bne"
| Tail, IfFLE(x, y, e1, e2) ->
- Printf.fprintf oc "\tfcmpu\tcr7, %s, %s\n" (reg x) (reg y);
+ Printf.fprintf oc "\tfcmp %s, %s\n" (reg x) (reg y);
g'_tail_if oc e1 e2 "ble" "bgt"
| NonTail(z), IfEq(x, V(y), e1, e2) ->
Printf.fprintf oc "\tcmp %s, %s\n" (reg x) (reg y);
@@ -175,10 +175,10 @@ and g' oc = function (* 各命令のアセンブリ生成 (caml2html: emit_gprim
Printf.fprintf oc "\tcmp %s, %d\n" (reg x) y;
g'_non_tail_if oc (NonTail(z)) e1 e2 "bge" "blt"
| NonTail(z), IfFEq(x, y, e1, e2) ->
- Printf.fprintf oc "\tfcmpu\tcr7, %s, %s\n" (reg x) (reg y);
+ Printf.fprintf oc "\tfcmp %s, %s\n" (reg x) (reg y);
g'_non_tail_if oc (NonTail(z)) e1 e2 "beq" "bne"
| NonTail(z), IfFLE(x, y, e1, e2) ->
- Printf.fprintf oc "\tfcmpu\tcr7, %s, %s\n" (reg x) (reg y);
+ Printf.fprintf oc "\tfcmp %s, %s\n" (reg x) (reg y);
g'_non_tail_if oc (NonTail(z)) e1 e2 "ble" "bgt"
(* 関数呼び出しの仮想命令の実装 (caml2html: emit_call) *)
| Tail, CallCls(x, ys, zs) -> (* 末尾呼び出し (caml2html: emit_tailcall) *)
実行してみる。すべて1が返ればOK
code:sh
$ make clean test/float-if && ./test/float-if
(省略)
sp = 0x16f0aee98, hp = 0x130008000
11111111
グローバル変数をアクセスできるようにする
min-rt をビルドしようとするとグローバル変数のアドレスを取得できなくてエラーになっていた。
adr 命令ではデータセグメントのアドレスが取得できないと予想。以下の実験を行いつつ adrp を使って関数とグローバル変数のアドレスを取得するように修正した。該当する min-rt のエラーは出なくなったので大丈夫そう。
code:diff
diff --git a/AArch64/emit.ml b/AArch64/emit.ml
index 715c22c..9dd4cb8 100644
--- a/AArch64/emit.ml
+++ b/AArch64/emit.ml
@@ -31,10 +31,6 @@ let reg r =
then String.sub r 1 (String.length r - 1)
else r
-let load_label r label =
- let r' = reg r in
- Printf.sprintf "\tadr %s, %s\n" r' label
-
(* 関数呼び出しのために引数を並べ替える(register shuffling) (caml2html: emit_shuffle) *)
let rec shuffle sw xys =
(* remove identical moves *)
@@ -75,8 +71,8 @@ and g' oc = function (* 各命令のアセンブリ生成 (caml2html: emit_gprim
Printf.fprintf oc "\tadrp %s, %s@PAGE\n" (reg reg_tmp) l;
Printf.fprintf oc "\tldr %s, %s, %s@PAGEOFF\n" (reg x) (reg reg_tmp) l | NonTail(x), SetL(Id.L(y)) ->
- let s = load_label x y in
- Printf.fprintf oc "%s" s
+ Printf.fprintf oc "\tadrp %s, %s@PAGE\n" (reg x) y;
+ Printf.fprintf oc "\tadd %s, %s, %s@PAGEOFF\n" (reg x) (reg x) y
| NonTail(x), Mr(y) when x = y -> ()
| NonTail(x), Mr(y) -> Printf.fprintf oc "\tmov %s, %s\n" (reg x) (reg y)
| NonTail(x), Neg(y) -> Printf.fprintf oc "\tneg\t%s, %s\n" (reg x) (reg y)
レイトレーサ (min-rt) を動かしてみる
test ディレクトリ以下のプログラムが動くようになったので、次はレイトレーサ (min-rt) を動かす。
グローバル変数置き場となる min-rt/AArch64/globals.s を用意し
code:min-rt/AArch64/globals.s
.data
.comm min_caml_objects, 480, 3
.comm min_caml_size, 16, 3
.comm min_caml_dbg, 8, 3
.comm min_caml_screen, 24, 3
.comm min_caml_vp, 24, 3
.comm min_caml_view, 24, 3
.comm min_caml_light, 24, 3
.comm min_caml_cos_v, 16, 3
.comm min_caml_sin_v, 16, 3
.comm min_caml_beam, 8, 3
.comm min_caml_and_net, 400, 3
.comm min_caml_or_net, 8, 3
.comm min_caml_temp, 112, 3
.comm min_caml_cs_temp, 128, 3
.comm min_caml_solver_dist, 8, 3
.comm min_caml_vscan, 24, 3
.comm min_caml_intsec_rectside, 8, 3
.comm min_caml_tmin, 8, 3
.comm min_caml_crashed_point, 24, 3
.comm min_caml_crashed_object, 8, 3
.comm min_caml_end_flag, 8, 3
.comm min_caml_viewpoint, 24, 3
.comm min_caml_nvector, 24, 3
.comm min_caml_rgb, 24, 3
.comm min_caml_texture_color, 24, 3
.comm min_caml_solver_w_vec, 24, 3
.comm min_caml_chkinside_p, 24, 3
.comm min_caml_isoutside_q, 24, 3
.comm min_caml_nvector_w, 24, 3
.comm min_caml_scan_d, 8, 3
.comm min_caml_scan_offset, 8, 3
.comm min_caml_scan_sscany, 8, 3
.comm min_caml_scan_met1, 8, 3
.comm min_caml_wscan, 24, 3
min-rt/Makefile を以下のように修正し
code:diff
diff --git a/min-rt/Makefile b/min-rt/Makefile
index 7157ccd..b33a548 100644
--- a/min-rt/Makefile
+++ b/min-rt/Makefile
@@ -23,7 +23,7 @@ ppmdiff: ppm.ml diff.ml
time ./min-rt.min-caml < $< > $@.tmp
mv $@.tmp $@
min-rt.min-caml: min-rt.s globals.s ../libmincaml.S ../stub.c
- gcc -m32 -g -O2 -Wall $^ -lm -o min-rt.min-caml
+ gcc -g -O2 -Wall $^ -lm -o min-rt.min-caml
min-rt.s: min-rt.ml ../min-caml
../min-caml -inline 100 min-rt
ビルドしてみる。
code:sh
make min-caml
cd min-rt
make min-rt.min-caml
以下のようなエラーが出力された。
code:sh
Undefined symbols for architecture arm64:
"min_caml_abs_float", referenced from:
beq_cont.5729 in min-rt-a00942.o
ble_else.5730 in min-rt-a00942.o
beq_cont.5740 in min-rt-a00942.o
ble_else.5741 in min-rt-a00942.o
beq_cont.5751 in min-rt-a00942.o
ble_else.5752 in min-rt-a00942.o
is_rect_outside.2070 in min-rt-a00942.o
...
"min_caml_atan", referenced from:
beq_else.5878 in min-rt-a00942.o
ble_cont.5882 in min-rt-a00942.o
"min_caml_cos", referenced from:
read_environ.2029 in min-rt-a00942.o
beq_else.5713 in min-rt-a00942.o
beq_else.5876 in min-rt-a00942.o
(maybe you meant: min_caml_cos_v)
"min_caml_float_of_int", referenced from:
ble_else.5921 in min-rt-a00942.o
ble_else.5923 in min-rt-a00942.o
scan_start.2139 in min-rt-a00942.o
"min_caml_floor", referenced from:
utexture.2118 in min-rt-a00942.o
ble_cont.5865 in min-rt-a00942.o
beq_else.5876 in min-rt-a00942.o
ble_cont.5882 in min-rt-a00942.o
ble_cont.5884 in min-rt-a00942.o
"min_caml_int_of_float", referenced from:
write_rgb.2131 in min-rt-a00942.o
ble_cont.5916 in min-rt-a00942.o
ble_cont.5918 in min-rt-a00942.o
"min_caml_print_byte", referenced from:
ble_cont.5916 in min-rt-a00942.o
ble_cont.5918 in min-rt-a00942.o
ble_cont.5920 in min-rt-a00942.o
write_ppm_header.2133 in min-rt-a00942.o
"min_caml_read_float", referenced from:
read_environ.2029 in min-rt-a00942.o
beq_else.5693 in min-rt-a00942.o
ble_cont.5696 in min-rt-a00942.o
beq_else.5697 in min-rt-a00942.o
"min_caml_read_int", referenced from:
read_nth_object.2031 in min-rt-a00942.o
beq_else.5693 in min-rt-a00942.o
read_net_item.2037 in min-rt-a00942.o
"min_caml_sin", referenced from:
read_environ.2029 in min-rt-a00942.o
beq_else.5713 in min-rt-a00942.o
beq_else.5863 in min-rt-a00942.o
(maybe you meant: min_caml_sin_v)
"min_caml_sqrt", referenced from:
normalize_vector.2022 in min-rt-a00942.o
ble_else.5767 in min-rt-a00942.o
beq_else.5876 in min-rt-a00942.o
beq_else.5878 in min-rt-a00942.o
ble_cont.5882 in min-rt-a00942.o
ble_else.5921 in min-rt-a00942.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
以下の関数が足りてないので libmincaml.c に実装する。
min_caml_abs_float
min_caml_atan
min_caml_cos
min_caml_float_of_int
min_caml_floor
min_caml_int_of_float
min_caml_print_byte
min_caml_read_float
min_caml_read_int
min_caml_sin
min_caml_sqrt
code:diff
diff --git a/AArch64/libmincaml.c b/AArch64/libmincaml.c
index 147e991..cb89c1c 100644
--- a/AArch64/libmincaml.c
+++ b/AArch64/libmincaml.c
@@ -1,4 +1,5 @@
+#include <math.h>
// NOTE: コンパイル後のシンボルのプリフィックスに _ がつくのを避ける
void min_caml_print_int(long n) asm("min_caml_print_int");
@@ -6,6 +7,18 @@ void min_caml_print_newline() asm("min_caml_print_newline");
long* min_caml_create_array(long number_of_element, long init_value) asm("min_caml_create_array");
double* min_caml_create_float_array(long number_of_element, double float_value) asm("min_caml_create_float_array");
long min_caml_truncate() asm("min_caml_truncate");
+void min_caml_print_float(double d) asm("min_caml_print_float");
+void min_caml_print_byte(long n) asm("min_caml_print_byte");
+long min_caml_read_int() asm("min_caml_read_int");
+double min_caml_read_float() asm("min_caml_read_float");
+double min_caml_atan(double x) asm("min_caml_atan");
+double min_caml_cos(double x) asm("min_caml_cos");
+double min_caml_floor(double x) asm("min_caml_floor");
+double min_caml_sin(double x) asm("min_caml_sin");
+double min_caml_abs_float(double x) asm("min_caml_abs_float");
+double min_caml_float_of_int(long n) asm("min_caml_float_of_int");
+long min_caml_int_of_float(double d) asm("min_caml_int_of_float");
+double min_caml_sqrt(double d) asm("min_caml_sqrt");
void min_caml_print_int(long n) {
printf("%ld", n);
@@ -43,7 +56,7 @@ double* min_caml_create_float_array(long number_of_element, double float_value)
asm volatile ("mov %0, x27" : "=r"(heap_ptr));
// Array の先頭アドレスを取得
- long *array_ptr = heap_ptr;
+ double *array_ptr = heap_ptr;
for (long i = 0l; i < number_of_element; i++) {
// Array へ書き込んだ後、ヒープの先頭アドレスを8バイト進める
@@ -61,3 +74,65 @@ double* min_caml_create_float_array(long number_of_element, double float_value)
long min_caml_truncate(double d) {
return (long)d;
}
+
+void min_caml_print_float(double d) {
+ printf("%lf", d);
+}
+
+void min_caml_print_byte(long n) {
+ putchar(n);
+}
+
+long min_caml_read_int() {
+ long l;
+ // fscanf(fp, "%ld", &l);
+ scanf("%ld", &l);
+ return l;
+}
+
+double min_caml_read_float() {
+ double d;
+ // fscanf(fp, "%lf", &d);
+ scanf("%lf", &d);
+ return d;
+}
+
+// atan
+double min_caml_atan(double x) {
+ return atan(x);
+}
+
+// cos
+double min_caml_cos(double x) {
+ return cos(x);
+}
+
+// floor
+double min_caml_floor(double x) {
+ return floor(x);
+}
+
+// sin
+double min_caml_sin(double x) {
+ return sin(x);
+}
+
+// abs_float
+double min_caml_abs_float(double x) {
+ return fabs(x);
+}
+
+// float_of_int
+double min_caml_float_of_int(long n) {
+ return (double)n;
+}
+
+// int_of_float
+long min_caml_int_of_float(double d) {
+ return (long)d;
+}
+
+// sqrt
+double min_caml_sqrt(double d) {
+ return sqrt(d);
+}
ビルドしてみる。
code:sh
$ cd ~/src/min-caml-aarch64/
$ gcc -S AArch64/libmincaml.c -o AArch64/libmincaml.S
$ make clean min-caml
$ make clean min-rt.min-caml
$ cd min-rt
$ make clean min-rt.min-caml
ビルドできたので、実行してみる。
code:sh
$ ./min-rt.min-caml < contest.sld > contest.ppm
動いた!やったね!!
https://gyazo.com/6707ce3a47b32b00326689b2c293dcd3